module Main {
  type @getConfig = (string): string
  type @isCertMode = (): boolean
  type @getTimestamp = (): string
  type @sign = (map[string]string, map[string]any, map[string]string, string): string
  type @getMerchantCertSN = (): string
  type @getAlipayRootCertSN = (): string
  type @toUrlEncodedRequestBody = (map[string]any): bytes
  type @readAsJson = ($Response, string): object
  type @getAlipayCertSN = (object): string
  type @extractAlipayPublicKey = (string): string
  type @verify = (object, string): boolean
  type @toRespModel = (object): object
  type @getSdkVersion = (): string

  init(); 

  model TradeFundBill {
    fundChannel: string(name='fund_channel'),
    bankCode: string(name='bank_code'),
    amount: string(name='amount'),
    realAmount: string(name='real_amount')
  }

  model VoucherDetail {
    id: string(name='id'),
    name: string(name='name'),
    type: string(name='type'),
    amount: string(name='amount'),
    merchantContribute: string(name='merchant_contribute'),
    otherContribute: string(name='other_contribute'),
    memo: string(name='memo'),
    templateId: string(name='template_id'),
    purchaseBuyerContribute: string(name='purchase_buyer_contribute'),
    purchaseMerchantContribute: string(name='purchase_merchant_contribute'),
    purchaseAntContribute: string(name='purchase_ant_contribute')
  }

  model AlipayTradePayResponse {
    httpBody: string(name='http_body', description='响应原始字符串'),
    code: string(name='code'),
    msg: string(name='msg'),
    subCode: string(name='sub_code'),
    subMsg: string(name='sub_msg'),

    tradeNo: string(name='trade_no'),
    outTradeNo: string(name='out_trade_no'),
    buyerLogonId: string(name='buyer_logon_id'),
    settleAmount: string(name='settle_amount'),
    payCurrency: string(name='pay_currency'),
    payAmount: string(name='pay_amount'),
    settleTransRate: string(name='settle_trans_rate'),
    transPayRate: string(name='trans_pay_rate'),
    totalAmount: string(name='total_amount'),
    transCurrency: string(name='trans_currency'),
    settleCurrency: string(name='settle_currency'),
    receiptAmount: string(name='receipt_amount'),
    buyerPayAmount: string(name='buyer_pay_amount'),
    pointAmount: string(name='point_amount'),
    invoiceAmount: string(name='invoice_amount'),
    gmtPayment: string(name='gmt_payment'),
    fundBillList: [ TradeFundBill ](name='fund_bill_list'),
    cardBalance: string(name='card_balance'),
    storeName: string(name='store_name'),
    buyerUserId: string(name='buyer_user_id'),
    discountGoodsDetail: string(name='discount_goods_detail'),
    voucherDetailList: [ VoucherDetail ](name='voucher_detail_list'),
    advanceAmount: string(name='advance_amount'),
    authTradePayMode: string(name='auth_trade_pay_mode'),
    chargeAmount: string(name='charge_amount'),
    chargeFlags: string(name='charge_flags'),
    settlementId: string(name='settlement_id'),
    businessParams: string(name='business_params'),
    buyerUserType: string(name='buyer_user_type'),
    mdiscountAmount: string(name='mdiscount_amount'),
    discountAmount: string(name='discount_amount'),
    buyerUserName: string(name='buyer_user_name')
  }

    model AlipayTradePrecreateResponse {
    httpBody: string(name='http_body', description='响应原始字符串'),
    code: string(name='code'),
    msg: string(name='msg'),
    subCode: string(name='sub_code'),
    subMsg: string(name='sub_msg'),

    outTradeNo: string(name='out_trade_no'),
    qrCode: string(name='qr_code'),
  }


  api pay(subject: string, outTradeNo: string, totalAmount: string, authCode: string): AlipayTradePayResponse {
    var systemParams: map[string]string = {
      method = 'alipay.trade.pay',

      app_id = @getConfig('appId'),
      timestamp = @getTimestamp(),
      format = 'json',
      version = '1.0',
      alipay_sdk = @getSdkVersion(),
      charset = 'UTF-8',
      sign_type = @getConfig('signType'),
      app_cert_sn = @getMerchantCertSN(),
      alipay_root_cert_sn = @getAlipayRootCertSN()
    };

    var bizParams: map[string]any = {
      subject = subject,
      out_trade_no = outTradeNo,
      total_amount = totalAmount,
      auth_code = authCode,
      scene = 'bar_code'
    };

    var textParams: map[string]string = {
    };

    protocol = @getConfig('protocol');
    method = 'POST';
    pathname = '/gateway.do';

    headers = {
      host = @getConfig('gatewayHost'),
      content-type = 'application/x-www-form-urlencoded;charset=utf-8'
    };

    query = {
      sign = @sign(systemParams, bizParams, textParams, @getConfig('merchantPrivateKey')),
      ... systemParams,
      ... textParams
    };

    body = @toUrlEncodedRequestBody(bizParams);
  } returns {
    var respMap: object = @readAsJson(__response, "alipay.trade.pay");

    if (@isCertMode()) {
      if (@verify(respMap, @extractAlipayPublicKey(@getAlipayCertSN(respMap)))) {
        return @toRespModel(respMap);
      } 
    } else {
      if (@verify(respMap, @getConfig('alipayPublicKey'))) {
        return @toRespModel(respMap);
      } 
    }
    
    throw {
      message = '验签失败，请检查支付宝公钥设置是否正确。'
    }
    
  } runtime {
    connectTimeout = 15000,
    readTimeout = 15000,
    retry = {
      maxAttempts = 0
    }
  }

  api preCreate(subject: string, outTradeNo: string, totalAmount: string): AlipayTradePrecreateResponse {
    var systemParams: map[string]string = {
      method = 'alipay.trade.precreate',

      app_id = @getConfig('appId'),
      timestamp = @getTimestamp(),
      format = 'json',
      version = '1.0',
      alipay_sdk = @getSdkVersion(),
      charset = 'UTF-8',
      sign_type = @getConfig('signType'),
      app_cert_sn = @getMerchantCertSN(),
      alipay_root_cert_sn = @getAlipayRootCertSN()
    };

    var bizParams: map[string]any = {
      subject = subject,
      out_trade_no = outTradeNo,
      total_amount = totalAmount
    };

    var textParams: map[string]string = {
    };

    protocol = @getConfig('protocol');
    method = 'POST';
    pathname = '/gateway.do';

    headers = {
      host = @getConfig('gatewayHost'),
      content-type = 'application/x-www-form-urlencoded;charset=utf-8'
    };

    query = {
      sign = @sign(systemParams, bizParams, textParams, @getConfig('merchantPrivateKey')),
      ... systemParams,
      ... textParams
    };

    body = @toUrlEncodedRequestBody(bizParams);
  } returns {
    var respMap: object = @readAsJson(__response, "alipay.trade.precreate");

    if (@isCertMode()) {
      if (@verify(respMap, @extractAlipayPublicKey(@getAlipayCertSN(respMap)))) {
        return @toRespModel(respMap);
      }
    } else {
      if (@verify(respMap, @getConfig('alipayPublicKey'))) {
        return @toRespModel(respMap);
      }
    }

    throw {
      message = '验签失败，请检查支付宝公钥设置是否正确。'
    }

  } runtime {
    connectTimeout = 15000,
    readTimeout = 15000,
    retry = {
      maxAttempts = 0
    }
  }

}